package main

import (
	"fmt"
	"jvm/classfile"
	"jvm/classpath"
	"strings"
)

func main() {
	cmd := parseCmd()
	if cmd.versionFlag {
		fmt.Println("version 0.0.1")
	} else if cmd.helpFlag || cmd.class == "" {
		printUsage()
	} else {
		startJVM(cmd)
	}

}
func startJVM(cmd *Cmd) {
	cp := classpath.Parse(cmd.XjreOption, cmd.cpOption) //classpath
	className := strings.Replace(cmd.class, ".", "/", -1)
	data, err := cp.GetBytecode(className)
	if err != nil {
		panic("找不到类")
	}
	parseBytecode(data)
}

func parseBytecode(bytecode []byte) {
	classfile, err := classfile.ParseBytecode(bytecode)
	if err != nil {
		panic(err)
	}
	printInfo(classfile)

}
func printInfo(classfile *classfile.ClassFile) {
	printVersion(classfile)
	printConstantPool(classfile)
	printAccessFlags(classfile)
	printThisClass(classfile)
	printSuperClass(classfile)
	printInterfaces(classfile)
	printFields(classfile)
	printMethods(classfile)
	printAttributes(classfile)

}
func printVersion(classfile *classfile.ClassFile) {
	fmt.Printf("版本：%d.%d\n", classfile.MajorVersion(), classfile.MinorVersion())
}
func printConstantPool(classfile *classfile.ClassFile) {
	cp := classfile.ConstantPool()
	fmt.Println("Constant pool:", len(cp))
	for index, val := range cp {
		if index == 0 || val == nil{
			continue
		}
		fmt.Printf("#%d = ", index)
		val.Print()
	}
}
func printAccessFlags(classfile *classfile.ClassFile) {
	fmt.Println("flags:", classfile.AccessFlags())
}
func printThisClass(cf *classfile.ClassFile) {
	classIndex := cf.ThisClass()
	cp := cf.ConstantPool()
	class := cp.GetConstantInfo(classIndex).(*classfile.ConstantClass)
	fmt.Printf("this_class: #%d\t\t\n", classIndex)
	class.Print()
}
func printSuperClass(cf *classfile.ClassFile) {
	classIndex := cf.SuperClass()
	cp := cf.ConstantPool()
	class := cp.GetConstantInfo(classIndex).(*classfile.ConstantClass)
	fmt.Printf("super_class: #%d\t\t\n", classIndex)
	class.Print()
}
func printInterfaces(cf *classfile.ClassFile) {
	cp := cf.ConstantPool()
	fmt.Println("interfaces:", len(cf.Interfaces()))
	for index, val := range cf.Interfaces() {
		class := cp.GetConstantInfo(val).(*classfile.ConstantClass)
		fmt.Printf("#%d\n", index)
		class.Print()
	}
}
func printFields(classfile *classfile.ClassFile) {
	fmt.Println("fields:", len(classfile.Fields()))
	for index, val := range classfile.Fields() {
		fmt.Printf("#%d{\n", index)
		val.Print()
		fmt.Println("}")
	}
}
func printMethods(classfile *classfile.ClassFile) {
	fmt.Println("methods:", len(classfile.Methods()))
	for index, val := range classfile.Methods() {
		fmt.Printf("#%d{\n", index)
		val.Print()
		fmt.Println("}")
	}
}
func printAttributes(classfile *classfile.ClassFile) {
	fmt.Println("attributes:", len(classfile.Attributes()))
	for index, val := range classfile.Attributes() {
		fmt.Printf("#%d{\n", index)
		val.Print()
		fmt.Println("}")
	}
}
